home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / GopherTools / jughead / jughead.0.9 / jughead.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-22  |  31.4 KB  |  925 lines

  1. /*****************************************************************************
  2.  * File:    jughead.c
  3.  *
  4.  * Author:    Rhett "Jonzy" Jones
  5.  *        jonzy@cc.utah.edu
  6.  *
  7.  * Date:    February 17, 1993
  8.  *
  9.  * Modified:    February 27, 1993 by Rhett "Jonzy" Jones
  10.  *        To support both the 'h' and 'v' flags, and to no longer
  11.  *         write recurrsivly to temporary files.  Now I only write
  12.  *        to a single temporary file.
  13.  *
  14.  *        March 3, 1993, by Rhett "Jonzy" Jones
  15.  *        Added support for the 'b' flag.
  16.  *
  17.  *        March 10, 1993, by Rhett "Jonzy" Jones.
  18.  *        Added support for the 'B' and 'l' flags.
  19.  *
  20.  *        March 13, 1993, by Rhett "Jonzy" Jones.
  21.  *        Fixed some bugs, optimized some routines, and rewrote
  22.  *        DoSystemCall().  Removed Lowercase() and changed calls
  23.  *        calls to this routine to StrToLower(), which is defined
  24.  *        "search.c".  Modified BeenHereB4() to handle the cases
  25.  *        where the selector string is "/" and "1/", which is the
  26.  *        same as "".
  27.  *
  28.  *        March 15, 1993, by Rhett "Jonzy" Jones.
  29.  *        Relocated the changes made to BeenHereB4() to a new
  30.  *        routine EmptyStringCheck() so all occurances of "/",
  31.  *        "1/", and "1" get mapped to "".  I should mention I just
  32.  *        discovered "1" gets handled like "/", "1/", and "".  Hmm.
  33.  *
  34.  *        March 18, 1993, by Rhett "Jonzy" Jones.
  35.  *        Added HostField2Lower() to make sure the host field gets
  36.  *        mapped to lowercase, which is needed when building the
  37.  *        index so that sort will eliminate all duplicates.
  38.  *        Fixed the system call to "sort" to only sort on the selector
  39.  *        string and beyond.  Also defined CATCOMMAND, RMCOMMAND, and
  40.  *        SORTCOMMAND for use when calling DoSystemCall().
  41.  *
  42.  *        March 21, 1993, by Rhett "Jonzy" Jones.
  43.  *        GetParamsFromStdin() now only prints the message informing
  44.  *        the user to enter control-D when finished, only if we are
  45.  *        getting the information from stdin and not a file.
  46.  *
  47.  *        March 27, 1993, by Rhett "Jonzy" Jones.
  48.  *        Moved the definitions of VERSION, CATCOMMAND, RMCOMMAND,
  49.  *        SORTCOMMAND, and TMPFILENAME to the Makefile.  Changed the
  50.  *        name of DoWeRecurse() to DoWeTraverse().  Added CantGet2Host()
  51.  *        nogoHead, and nogoTail to support the ability of not attempting
  52.  *        to connect to a host we could not connect previously.
  53.  *
  54.  *        March 28, 1993, by Rhett "Jonzy" Jones.
  55.  *        Added HandleIndention(), and modified DoWeTraverse() to print
  56.  *        "<< see line # >>" with the proper indention if we have seen
  57.  *        this directory before.  Added support for the -n flag.  If we
  58.  *        received a line from a server which did not have the host or
  59.  *        port string, the line is now not processed.  Fixed a problem of
  60.  *        not comparing the hosts correctly, which was fixed by converting
  61.  *        the incoming host name to lowercase.  If a menu path has been
  62.  *        traversed previously, it will no longer be traversed again and a
  63.  *        message stating what line to view will be printed with the
  64.  *        proper indention.  When not running to build the index table or
  65.  *        as a search engine, jughead now prints a note if hosts were
  66.  *        encountered that could not be connected to, and just prior to
  67.  *        termination displays the hosts it could not connect to.
  68.  *
  69.  *        March 31, 1993, by Mic Kaczmarczik: mic@bongo.cc.utexas.edu
  70.  *        Added support for an optional -p port flag when running as a
  71.  *        search engine.  Added the variable 'searchPort', modified
  72.  *        UsageError(), GetArguments() and the call to DoSearch() in
  73.  *        main().
  74.  *
  75.  *        April 1, 1993, by Rhett "Jonzy" Jones.
  76.  *        Added support for the -t flag which prints the time required
  77.  *        to either read in the index table, build the data file, or
  78.  *        process a menu from a given gopher server.  Added support for
  79.  *        the -a and -A flags which print the dirTree with the number of
  80.  *        directories served or the directories served respectivly.
  81.  *        Made 'buildIndex' and 'doSearch' global variables instead of
  82.  *        local to main() and adjusted GetArguments() to reflect the
  83.  *        change.  No longer sort the datafile to datafile.sorted when
  84.  *        using the -b option.  Instead dataFile gets sorted into
  85.  *        dataFile.
  86.  *
  87.  *        April 20, 1993, by Rhett "Jonzy" Jones.
  88.  *        Added LooksGood() to make sure we received a valid line of
  89.  *        of data from the server.  This routine was written because
  90.  *        it was found the PC Gopher Server did not follow gopher
  91.  *        protocol.  Added the variable menuFlag to prevent printing of
  92.  *        the menus when building the dataFile.  Fixed a bug that would
  93.  *        not correctly validate the port for the exceptions host, which
  94.  *        is the host and port to not traverse.
  95.  *
  96.  *        May 3, 1993, by Rhett "Jonzy" Jones.
  97.  *        Modified LooksGood() to immediatly return false if we acquired
  98.  *        a null string.  This fixed a core dump when attempting to
  99.  *        retrieve an empty directory from a gopher+ server.  Thanks
  100.  *        lindner@boombox.micro.umn.edu for the bug report.
  101.  *
  102.  *        May 5, 1993, by Rhett "Jonzy" Jones.
  103.  *        Added support for -X which is a selector string to not traverse.
  104.  *        A quick hack to not traverse any selector strings that begin
  105.  *        with "ftp:".  Example: jughead soar.cc.utah.edu -X "ftp:*".
  106.  *        The variable used for this support is 'exceptionSelStr' and
  107.  *        does supports wildcarding.
  108.  *
  109.  *        May 20, 1993, by Rhett "Jonzy" Jones.
  110.  *        Moved UsageError(), PrintVersion(), GetParamsFromStdin(), and
  111.  *        GetArguments() to getargs.c, due in part to rewritting some of
  112.  *        these routines.  Removed initialization of global variables at
  113.  *        the time of declaration, and added InitializeTheWorld() to
  114.  *        accommodate the initialization.  Added the variable username
  115.  *        to support -u username and allow jughead to act as a search
  116.  *        engine running with a uid of username.
  117.  *
  118.  *        May 22, 1993, by Rhett "Jonzy" Jones.
  119.  *        Removed the variables 'exceptionHost', 'exceptionPort', and
  120.  *        'exceptionSelStr', and the routine ValidSelStr(), added the
  121.  *        variable 'nogos' to support multiple exception items.  Thus
  122.  *        jughead now can support multiple hosts and ports not to traverse
  123.  *        as well as multiple selection strings to to traverse.
  124.  *
  125.  * Description:    Jonzy's Universal Gopher Hierarchy Excavation And Display.
  126.  *        Excavates through gopher menus and displays the hierarchy
  127.  *        of the menus encountered.
  128.  *
  129.  * Routines:    void    HandleIndention(int indent);
  130.  *        short    Host2Search(char *s);
  131.  *        List    *CreateNode(char *sStr,char *hStr,char *pStr);
  132.  *        List    *InsertNode(List *tail,List *node);
  133.  *        List    *RemoveNode(List *tail);
  134.  *        short    BeenHereB4(char *sStr,char *hStr,char *pStr,List *head);
  135.  *        short    CantGet2Host(List *nogoList,char *sStr,char *Str,
  136.  *                     char *pStr);
  137.  *        short    DoWeTraverse(char type,char *sStr,char *hStr,
  138.  *                     char *pStr,List *head,int indent);
  139.  *        void    PrintPath(char *p,int indent);
  140.  *        void    PrintItem(char *dStr,int indent);
  141.  *        void    BuildPath(char *dStr,int indent);
  142.  *        void    InitPath(void);
  143.  *        void    DestroyPath(int indent);
  144.  *        char    *EmptyStringCheck(char *sStr);
  145.  *        char    *HostField2Lower(char *line);
  146.  *        int    LooksGood(char **rsltLine,FILE *rdPtr);
  147.  *        void    ProcessMenu(char *selStr,char *hostStr,char *portStr,
  148.  *                    int indent);
  149.  *        void    PostTime2Process(void);
  150.  *        void    InitializeTheWorld();
  151.  *        int    main(int argc,char *argv[]);
  152.  *
  153.  * Bugs:    No known bugs.
  154.  *
  155.  * Copyright:    Copyright 1993, University of Utah Computer Center.
  156.  *        This source may be freely distributed as long as this copyright
  157.  *         notice remains intact, and is in no way used for any monetary
  158.  *         gain, by any institution, business, person, or persons.
  159.  *
  160.  * TODO:    Either reenable or remove support for onlyDoHosts and
  161.  *        onlyDoHostsT.
  162.  ****************************************************************************/
  163.  
  164. #ifdef NEXT
  165. #    include <libc.h>
  166. #else
  167. #    include <stdlib.h>
  168. #endif
  169. #include <signal.h>
  170. #include <stdio.h>
  171. #include <string.h>
  172. #include <sys/file.h>
  173. #include <sys/stat.h>
  174. #include <sys/wait.h>
  175. #include <time.h>
  176.  
  177. #include "jughead.h"
  178. #include "dirTree.h"
  179. #include "tree.h"
  180.  
  181. extern char *GetString();    /* Defined in "sockets.c". */
  182.  
  183. FILE    *wtPtr,            /* File pointer for writing to 'theHost'. */
  184.     *rdPtr;            /* File pointer for reading from 'theHost'. */
  185. char    buffer[BUFFERSIZE],    /* The output from the machine. */
  186.     path[BUFFERSIZE],    /* The path to print if using 'onlyDoHostsT'. */
  187.     pathPrinted[50],    /* Did we print the path(s) if using 'onlyDoHostsT'. */
  188.     *searchHosts[MAXHOSTS],    /* Hosts to search. */
  189.     *initialHost,        /* The initial host we connected to. */
  190.     *selStr,        /* The selector string. */
  191.     *hostStr,        /* The host string. */
  192.     *portStr,        /* The port string. */
  193.     *fileName,        /* Name of the file to open or create. */
  194.     *userName;        /* Name of the user to use with -S. */
  195. int    numSearchHosts,        /* The number of hosts to search. */
  196.     debug,            /* Are we debugging? */
  197.     info4dirsOnly,        /* Do we print host info for directories only? */
  198.     info4allItems,        /* Do we print host info for all the items? */
  199.     listHosts,        /* Do we print only the hosts accessed? */
  200.     listHostsNPorts,    /* Do we print only the hosts and ports accessed? */
  201.     onlyDoHosts,        /* Do we print info for selected hosts only? */
  202.     onlyDoHostsT,        /* Same as onlyDoHosts but traverse anyway. */
  203.     buildDataFile,        /* Are we building the dataFile? */
  204.     menuFlag,        /* Do we display the menus? */
  205.     printLineNumbers,    /* Do we print line numbers? */
  206.     searchPort,        /* Default port for -S flag */
  207.     printDTree,        /* Do we print the dirTree with the number of directories served? */
  208.     printDTreeDirs,        /* Do we print the dirTree along with the directories served? */
  209.     time2process;        /* Do we calculate the time for a certain run? */
  210. short    buildIndex,        /* Do we build the index table? */
  211.     doSearch;        /* Are we doing the search stuff? */
  212. List    *nogos = (List *)NIL,    /* Information about who to not traverse.*/
  213.     *head = (List *)NIL,    /* The head of the current menu path list. */
  214.     *tail = (List *)NIL,    /* The tail of the current menu path list. */
  215.     *nogoHead = (List *)NIL,/* Head of the can't connect to host and port list. */
  216.     *nogoTail = (List *)NIL;/* Tail of the can't connect to host and port list. */
  217. long    seenDirB4;        /* Have we seen this before? */
  218. time_t    startTime;        /* The time a run was started, for use with 'time2process'. */
  219.  
  220. extern long    lineNumber;    /* Defined in dirTree.c. */
  221.  
  222. /*****************************************************************************
  223.  * HandleIndention prints 'indent' number of indentions to stdout.  This
  224.  * routine is used to keep directory contents lined up horizontaly.
  225.  ****************************************************************************/
  226. void HandleIndention(indent)
  227.     int    indent;        /* The level of indention. */
  228. {    int    numIndents;    /* The number of indentions to add to the path. */
  229.  
  230.     /* Indent the data 'indent' number of indentions. */
  231.     for (numIndents = 0; numIndents < indent; numIndents++)
  232.         fprintf(stdout,"%s",INDENTSTR);
  233.  
  234. }    /* HandleIndention */
  235.  
  236. /*****************************************************************************
  237.  * Host2Search returns true if the hosts 's' is a member of 'searchHosts',
  238.  * otherwise it returns false.
  239.  ****************************************************************************/
  240. short Host2Search(s)
  241.     char    *s;    /* Is this in 'searchHosts'? */
  242. {    int    i;    /* A loop counter. */
  243.  
  244.     for (i = 0; i < numSearchHosts; i++)
  245.         if (StrRcmp(searchHosts[i],s))
  246.         /* if (!strcmp(s,searchHosts[i])) */
  247.             return(1);
  248.     return(0);
  249.  
  250. }    /* Host2Search */
  251.  
  252. /*****************************************************************************
  253.  * CreateNode returns a newly created and initialized node for the list.
  254.  ****************************************************************************/
  255. List *CreateNode(sStr,hStr,pStr)
  256.     char    *sStr,        /* The selector string. */
  257.         *hStr,        /* The host string. */
  258.         *pStr;        /* The port string. */
  259. {    List    *node;        /* The node we are returning. */
  260.  
  261.     if (node = (List *)malloc(sizeof(List)))
  262.         if (node->info.sStr = (char *)malloc(strlen(sStr) + 1))
  263.             {
  264.             strcpy(node->info.sStr, sStr);
  265.             if (node->info.hStr = (char *)malloc(strlen(hStr) + 1))
  266.                 {
  267.                 strcpy(node->info.hStr, hStr);
  268.  
  269.                 if (node->info.pStr = (char *)malloc(strlen(pStr) + 1))
  270.                     {
  271.                     strcpy(node->info.pStr, pStr);
  272.                     node->next = node->last = (List *)NIL;
  273.                     return(node);
  274.                     }
  275.                 else
  276.                     {
  277.                     free(node->info.hStr);    node->info.hStr = (char *)NIL;
  278.                     free(node->info.sStr);    node->info.sStr = (char *)NIL;
  279.                     free(node);        node = (List *)NIL;
  280.                     }
  281.                 }
  282.             else
  283.                 {
  284.                 free(node->info.sStr);    node->info.sStr = (char *)NIL;
  285.                 free(node);        node = (List *)NIL;
  286.                 }
  287.             }
  288.         else
  289.             {
  290.             free(node);    node = (List *)NIL;
  291.             }
  292.  
  293.     fprintf(stderr,"error: CreateNode could not get memory for the node.\n");
  294.     return(node);
  295.  
  296. }    /* CreateNode */
  297.  
  298. /*****************************************************************************
  299.  * InsertNode inserts the node 'node' on the end of the list 'list'.
  300.  ****************************************************************************/
  301. List *InsertNode(tail,node)
  302.     List    *tail,        /* The tail of the list we are inserting into. */
  303.         *node;        /* The node we are inserting. */
  304. {
  305.     if (!node)
  306.         return(tail);
  307.  
  308.     tail->next = node;
  309.     node->last = tail;
  310.     return(node);
  311.  
  312. }    /* InsertNode */
  313.  
  314. /*****************************************************************************
  315.  * RemoveNode removes and frees up the memory occupied by the last item
  316.  * in the list, which is pointed to by 'tail'.
  317.  ****************************************************************************/
  318. List *RemoveNode(tail)
  319.     List    *tail;        /* The tail of the list we are inserting into. */
  320. {    List    *node;        /* The node to remove. */
  321.  
  322.     node = tail;
  323.     tail = tail->last;
  324.     tail->next = (List *)NIL;
  325.     free(node->info.sStr);        node->info.sStr = (char *)NIL;
  326.     free(node->info.hStr);        node->info.hStr = (char *)NIL;
  327.     free(node->info.pStr);        node->info.pStr = (char *)NIL;
  328.     free(node);            node = (List *)NIL;
  329.     return(tail);
  330.  
  331. }    /* RemoveNode */
  332.  
  333. /*****************************************************************************
  334.  * BeenHereB4 returns true if 'sStr', 'hStr', and 'pStr' are in the list
  335.  * pointed to by 'list'.  This is done so we will not travese a menu
  336.  * we are already looking at.  Otherwise it returns false because we
  337.  * are not looking at nor have been in this part of the tree.
  338.  ****************************************************************************/
  339. short BeenHereB4(sStr,hStr,pStr,list)
  340.     char    *sStr,        /* The selector string. */
  341.         *hStr,        /* The host string. */
  342.         *pStr;        /* The port string. */
  343.     List    *list;        /* Head of the list. */
  344. {
  345.     while (list)        /* See if we have been here before. */
  346.         {
  347.         if (!strcmp(list->info.sStr,sStr))
  348.             if (!strcmp(list->info.hStr,hStr))
  349.                 if (!strcmp(list->info.pStr,pStr))
  350.                     return(1);
  351.         list = list->next;
  352.         }
  353.     return(0);
  354.  
  355. }    /* BeenHereB4 */
  356.  
  357. /*****************************************************************************
  358.  * CantGet2Host returns true if we could not connect to 'hStr' out port 'pstr'
  359.  * previously.  Otherwise it returns false.  This routine calls BeenHereB4()
  360.  * and was written for readability only.
  361.  ****************************************************************************/
  362. short CantGet2Host(nogoList,sStr,hStr,pStr)
  363.     List    *nogoList;    /* List of hosts we can't connect to. */
  364.     char    *sStr,        /* The selector string. */
  365.         *hStr,        /* The host to connect to. */
  366.         *pStr;        /* The port to use. */
  367. {
  368.     return(BeenHereB4(sStr,hStr,pStr,nogoList));
  369.  
  370. }    /* CantGet2Host */
  371.  
  372. /*****************************************************************************
  373.  * DoWeTraverse returns true if we can look at this directory in the menu.
  374.  * Otherwise it returns false.  In otherwords return true if the item we
  375.  * have not looked at this directory yet, and the current entry is a
  376.  * directory, and the directory is from one of the hosts contained in
  377.  * 'hosts2search'.
  378.  ****************************************************************************/
  379. short DoWeTraverse(type,sStr,hStr,pStr,list,indent)
  380.     char    type,        /* What type of entry is this? */
  381.          *sStr,        /* The selector string. */
  382.         *hStr,        /* The host string. */
  383.         *pStr;        /* The port string. */
  384.     List    *list;        /* Head of the list. */
  385.     int    indent;        /* The level to indent if need be. */
  386. {    List    *t;        /* A temporary list of nogos.*/
  387.     char    *asterik;    /* Where is the asterik? */
  388.     size_t    numChars;    /* Number of characters to the asterik. */
  389.  
  390.     for (t = nogos; t; t = t->next)
  391.         if (t->info.sStr[0])
  392.             {
  393.             if (asterik = strchr(t->info.sStr,'*'))
  394.                 numChars = (size_t)(asterik - t->info.sStr);
  395.             else
  396.                 numChars = strlen(t->info.sStr);
  397.             if (!strncmp(t->info.sStr,sStr,numChars))
  398.                 return(0);
  399.             }
  400.         else if (t->info.hStr)
  401.             {
  402.             if (!strcmp(hStr,t->info.hStr) && !strcmp(pStr,t->info.pStr))
  403.                 return(0);
  404.             }
  405.  
  406. #if(1)    /* The NEW way. */
  407.     WaterTree(sStr,hStr,pStr);
  408.     if (type == A_DIRECTORY && Host2Search(hStr))
  409.         if (!(seenDirB4 = InDirTree(dirRoot,PSTR)))
  410.             {
  411.             dirRoot = BuildDirTree(dirRoot);
  412.             return(1);
  413.             }
  414.         else if (menuFlag)
  415.             {
  416.             HandleIndention(indent + 2 * printLineNumbers);
  417.             fprintf(stdout,"<< see line %ld >>\n",seenDirB4),++lineNumber;
  418.             }
  419. #else
  420.     if (type == A_DIRECTORY)
  421.         if (Host2Search(hStr) || (onlyDoHostsT && !strcmp(initialHost,hStr)))
  422.             return(!BeenHereB4(sStr,hStr,pStr,list));
  423. #endif
  424.     return(0);
  425.  
  426. }    /* DoWeTraverse */
  427.  
  428. /*****************************************************************************
  429.  * PrintPath prints the pathway, with the proper number of indentions for
  430.  * an item that has not had the pathway printed.
  431.  ****************************************************************************/
  432. void PrintPath(p,indent)
  433.     char    *p;        /* The path to print. */
  434.     int    indent;        /* The indention level. */
  435. {    char    *s;        /* The string to print out. */
  436.     int    i,j;        /* Loop counters. */
  437.     short    gotOne = 0;     /* Do we have a directory to print? */
  438.  
  439.     /* Find the directory we need to start printing if we have one. */
  440.     for (i = 0; i < indent; i++)
  441.         if (pathPrinted[i] == NOPE)
  442.             {
  443.             gotOne = 1;
  444.             break;
  445.             }
  446.  
  447.     if (gotOne)    /* Print the pathway. */
  448.         {
  449.         /* Skip pathways that have been printed. */
  450.         for (j = 0, s = p; j < i; j++)
  451.             {
  452.             for ( ; *s && *s != '\t'; s++)
  453.                 ;
  454.             if (*s)
  455.                 s++;
  456.             }
  457.  
  458.         /* Print the unprinted pathway(s). */
  459.         for ( ; i < indent; i++)
  460.             {
  461.             if (i)        /* Indent the directory. */
  462.                 fprintf(stdout,"%s",INDENTSTR);
  463.             for ( ; *s && *s != '\t'; s++)
  464.                 fprintf(stdout,"%c",*s);
  465.             if (*s)
  466.                 s++;
  467.             pathPrinted[i] = YEP;
  468.             fprintf(stdout,"/\n"),++lineNumber;
  469.             }
  470.         }
  471.  
  472. }    /* PrintPath */
  473.  
  474. /*****************************************************************************
  475.  * PrintItem prints the item with the proper number of indentions, as well
  476.  * as prints what type of item it is just like the unix gopher from Minnesota.
  477.  ****************************************************************************/
  478. void PrintItem(dStr,indent)
  479.     char    *dStr;        /* The display string. */
  480.     int    indent;        /* The level of indention. */
  481. {
  482.     if (printLineNumbers)    /* User wants the line numbers printed. */
  483.         fprintf(stdout,"%7ld ",lineNumber + 1);
  484.  
  485.     HandleIndention(indent);
  486.  
  487.     /* Print the menu title like a gopher menu. */
  488.     fprintf(stdout,"%s",dStr + 1);
  489.     switch (dStr[0])
  490.         {
  491.         case A_DIRECTORY:
  492.             fprintf(stdout,"/");
  493.             if (onlyDoHostsT)
  494.                 pathPrinted[indent] = YEP;
  495.             break;
  496.         case A_CSO:
  497.             fprintf(stdout," <CSO>");
  498.             break;
  499.         case A_TN3270:
  500.             fprintf(stdout," <3270>");
  501.             break;
  502.         case A_TELNET:
  503.             fprintf(stdout," <TEL>");
  504.             break;
  505.         case A_INDEX:
  506.             fprintf(stdout," <?>");
  507.             break;
  508.         case A_SOUND:
  509.             fprintf(stdout," <)");
  510.             break;
  511.         case A_FILE:
  512.             fprintf(stdout,".");
  513.             break;
  514.         case A_PCBIN:
  515.             fprintf(stdout," <PC Bin>");
  516.             break;
  517.         case A_UNIXBIN:
  518.             fprintf(stdout," <Bin>");
  519.             break;
  520.         case A_IMAGE:
  521.         case A_GIF:
  522.             fprintf(stdout," <Picture>");
  523.             break;
  524.         case A_MACHEX:
  525.             fprintf(stdout," <HQX>");
  526.             break;
  527.         default:
  528.             fprintf(stdout," <~%c~>",dStr[0]);
  529.             break;
  530.         }
  531.  
  532. }    /* PrintItem */
  533.  
  534. /*****************************************************************************
  535.  * BuildPath builds the pathways for items so we can print the items with
  536.  * the pathway when the 'O' option is used.
  537.  ****************************************************************************/
  538. void BuildPath(dStr,indent)
  539.     char    *dStr;        /* The string to add to the path. */
  540.     int    indent;        /* The level of indention. */
  541. {
  542.     if (indent)
  543.         strcat(path,"\t");
  544.     strcat(path,dStr);
  545.  
  546. }    /* BuildPath */
  547.  
  548. /*****************************************************************************
  549.  * InitPath resets the all path variables to zero.
  550.  ****************************************************************************/
  551. void InitPath()
  552. {    int    i;
  553.  
  554.     for (i = 0; i < 50; i++)
  555.         pathPrinted[i] = NOPE;
  556.     path[0] = '\0';
  557.  
  558. }    /* InitPath */
  559.  
  560. /*****************************************************************************
  561.  * DestroyPath destroys the last path within the pathway to an item.
  562.  ****************************************************************************/
  563. void DestroyPath(indent)
  564.     int    indent;        /* The level of indention. */
  565. {    char    *s;        /* A pointer into 'path'. */
  566.  
  567.     if (!indent)
  568.         InitPath();
  569.     else if ((s = strrchr(path,'\t')) > path)
  570.         {
  571.         *s = '\0';
  572.         pathPrinted[indent] = NOPE;
  573.         }
  574.  
  575. }    /* DestroyPath */
  576.  
  577. /*****************************************************************************
  578.  * EmptyStringCheck checks if the string 'sStr' is either "/", "1/", or "1",
  579.  * and if it is we return the emptystring "".  Otherwise 'sStr' gets returned
  580.  * unchanged.  The reason for this routine is to prevent a recursive menu
  581.  * loop from happening.  The gopher protocol says you must send the empty
  582.  * string to acquire the menu.  Well it looks like a unix server handles
  583.  * "", "/", "1/", and "1" all the same.  Hmm.
  584.  ****************************************************************************/
  585. static char *EmptyStringCheck(sStr)
  586.     char    *sStr;        /* The string we are testing. */
  587. {
  588.  
  589.     if (!strcmp(sStr,"/") || !strcmp(sStr,"1/") || !strcmp(sStr,"1"))
  590.         return(EMPTYSTRING);
  591.     return(sStr);
  592.  
  593. }    /* EmptyStringCheck */
  594.  
  595. /*****************************************************************************
  596.  * HostField2Lower returns the string passed in with the host field converted
  597.  * to lowercase.
  598.  ****************************************************************************/
  599. char *HostField2Lower(line)
  600.     char    *line;        /* The line we are looking at. */
  601. {    char    *s;        /* A position in 'line'. */
  602.  
  603.  
  604.     for (s = strchr(strchr(line,'\t') + 1,'\t') + 1; *s && *s != '\t'; s++)
  605.         *s = tolower(*s);
  606.  
  607.     return(line);
  608.  
  609. }    /* HostField2Lower */
  610.  
  611. /*****************************************************************************
  612.  * LooksGood returns true if we received a valid line from 'rdPtr', otherwise
  613.  * it returns false.  A valid line has the form:
  614.  *    dStr\tsStr\thStr\tpStr[\tmore]\r\n
  615.  * a invalid line, or we are done, has the form:
  616.  *    .\r\n
  617.  * or any line with no tabs, etc.
  618.  * This routine was written because the PC Gopher server does not follow
  619.  * gopher protocol, and sends the string:
  620.  *    Error: Could not find requested file\r\n.\r\n
  621.  * when it should look something like:
  622.  *    Error: could not find requested file\t\terror.host\t-1\r\n.\r\n
  623.  ****************************************************************************/
  624. static int LooksGood(rsltLine,rdPtr)
  625.     char    **rsltLine;    /* The line we are getting from 'rdPtr'. */
  626.     FILE    *rdPtr;        /* The file or socket we are reading from. */
  627. {    char    *s;        /* A position in 'rsltLine'. */
  628.     int    numTabs;    /* How many tabs are there? */
  629.  
  630.     /* Get the line of data from the server and make sure we got something. */
  631.     if (!(*rsltLine = GetString(rdPtr)))
  632.         return(0);
  633.  
  634.     /* Check of we are done. */
  635.     if (strstr(rsltLine,".\r"))
  636.         return(0);
  637.  
  638.     /* See if we have at least 3 tabs. */
  639.     for (s = *rsltLine, numTabs = 0; *s; s++)
  640.         if (*s == '\t')
  641.             numTabs++;
  642.     if (numTabs > 2)
  643.         return(1);
  644.  
  645.     /* We got something that is totaly out to lunch. */
  646.     return(0);
  647.  
  648. }    /* LooksGood */
  649.  
  650. /*****************************************************************************
  651.  * ProcessMenu processes the menu entity which should be a directory.  If
  652.  * the entity is not a directory ... well you know what they say, "garabage
  653.  * in ... garbage out.
  654.  * This code is ugly, but oh well such is life.
  655.  ****************************************************************************/
  656. void ProcessMenu(selStr,hostStr,portStr,indent)
  657.     char    *selStr,    /* Selection string to send. */
  658.         *hostStr,    /* The host to contact. */
  659.         *portStr;    /* The port to use. */
  660.     int    indent;        /* The level of indentation. */
  661. {    char    **data,        /* The data acquired from the host via the file. */
  662.         *rsltLine,    /* The resultant line of data. */
  663.         *dStr,        /* The display field. */
  664.         *sStr,        /* The selector field. */
  665.         *hStr,        /* The host field. */
  666.         *pStr;        /* The port field. */
  667.     FILE    *fPtr;        /* Pointer to the menu file. */
  668.     int    numItems,    /* Number of items in the menu. */
  669.         error = 0,    /* Did we encounter an error? */
  670.         i;        /* A loop counter. */
  671.  
  672.     if (!head)
  673.         head = tail = CreateNode(selStr,hostStr,OnlyDigits(portStr));
  674.     else
  675.         tail = InsertNode(tail,CreateNode(selStr,hostStr,OnlyDigits(portStr)));
  676.  
  677.     if (!dirRoot && !indent)
  678.         {
  679.         WaterTree(selStr,hostStr,portStr);
  680.         indent++;
  681.         lineNumber++;
  682.         if (menuFlag && printLineNumbers)    /* User wants the line numbers printed. */
  683.             fprintf(stdout,"%7ld ",lineNumber);
  684.         fprintf(stdout,"Gopher root is [%s] port = %s\n",hostStr,portStr);
  685.         dirRoot = BuildDirTree(dirRoot);
  686.         }
  687.  
  688.     if (ContactHost(hostStr,Str2Int(portStr)))
  689.         {
  690.         /* Write the information to a temporary file. */
  691.         if (fPtr = fopen(TMPFILENAME,"w"))
  692.             {
  693.             SendString(selStr);
  694.             SendString("\r\n");
  695.             for (numItems = 0; LooksGood(&rsltLine,rdPtr); numItems++)
  696.                 fprintf(fPtr,"%s",(buildDataFile) ? HostField2Lower(rsltLine) : rsltLine);
  697.             CloseReadNwriter();
  698.             fclose(fPtr);
  699.             if (buildDataFile)
  700.                 DoSystemCall(Mysprint(CATCOMMAND,TMPFILENAME,fileName));
  701.             if (debug)
  702.                 fprintf(stderr,"Connections are now closed with %d item%c found\n",
  703.                     numItems,numItems > 1 ? 's' : '\0');
  704.             }
  705.         else
  706.             error = fprintf(stderr,"error: ProcessMenu cannot create [%s]\n",TMPFILENAME);
  707.  
  708.         /* Read the temporary file into a dynamic array. */
  709.         if (!error && (data = (char **)malloc(numItems * sizeof(char *))))
  710.             {
  711.             if (fPtr = fopen(TMPFILENAME,"r"))
  712.                 {
  713.                 for (i = 0; i < numItems && !error; i++)
  714.                     if (data[i] = (char *)malloc((strlen(rsltLine = GetString(fPtr)) + 1) * sizeof(char)))
  715.                         strcpy(data[i],rsltLine);
  716.                     else
  717.                         {
  718.                         error = fprintf(stderr,"error: ProcessMenu cannot get memory for the %dth element\n");
  719.                         for ( ; i; i--)
  720.                             free(data[i]);
  721.                         free(data);
  722.                         }
  723.                 fclose(fPtr);
  724.                 DoSystemCall(Mysprint(RMCOMMAND,TMPFILENAME));
  725.                 }
  726.             else
  727.                 error = fprintf(stderr,"error: ProcessMenu cannot read [%s]\n",TMPFILENAME);
  728.             }
  729.         else if (!error && numItems)
  730.             error = fprintf(stderr,"error: ProcessMenu cannot get memory for the %d data items\n",numItems);
  731.  
  732.         if (!error)
  733.             {
  734.             for (i = 0; i < numItems; i++)
  735.                 {
  736.                 dStr = MyStrTok(data[i],'\t');
  737.                 sStr = EmptyStringCheck(MyStrTok(NULL,'\t'));
  738.                 hStr = StrToLower(MyStrTok(NULL,'\t'));
  739.                 pStr = OnlyDigits(MyStrTok(NULL,'\0'));
  740.  
  741.                 /* Make sure we were able to parse the line correctly. */
  742.                 if (!hStr[0] || !pStr[0])    /* Yipes!  Skip this item. */
  743.                     continue;
  744.  
  745.                 if (debug)
  746.                     {
  747.                     fprintf(stderr,"\tdStr = [%s]\n",dStr);
  748.                     fprintf(stderr,"\tsStr = [%s]\n",sStr);
  749.                     fprintf(stderr,"\thStr = [%s]\n",hStr);
  750.                     fprintf(stderr,"\tpStr = [%s]\n",pStr);
  751.                     }
  752.  
  753.                 if (listHosts)
  754.                     {
  755.                     char    s[1024];
  756.                     sprintf(s,"%s\t%s",hStr,pStr);
  757.                     BuildTree(&root,s,-1);
  758.                     }
  759.                 else if (menuFlag && (!onlyDoHosts || (onlyDoHosts && Host2Search(hStr))))
  760.                     {
  761.                     if (onlyDoHostsT)
  762.                         PrintPath(path,indent);
  763.  
  764.                     PrintItem(dStr,indent);
  765.  
  766.                     /* Do we print the host and port to the right of the item? */
  767.                     if (info4allItems || (info4dirsOnly && dStr[0] == A_DIRECTORY))
  768.                         fprintf(stdout,"\t%s %s",hStr,pStr);
  769.  
  770.                     fprintf(stdout,"\n"),++lineNumber;
  771.                     }
  772.  
  773.                 if (DoWeTraverse(dStr[0],sStr,hStr,pStr,head,indent + 1))
  774.                     {
  775.                     if (!listHosts && onlyDoHostsT)
  776.                         BuildPath(dStr + 1,indent);
  777.  
  778.                     if (!CantGet2Host(nogoHead,EMPTYSTRING,hStr,pStr))
  779.                         ProcessMenu(sStr,hStr,pStr,indent + 1);
  780.                     else
  781.                         fprintf(stderr,"warning: ProcessMenu could not previously connect to %s %s\n",hStr,pStr);
  782.  
  783.                     if (!listHosts &&  onlyDoHostsT)
  784.                         DestroyPath(indent);
  785.                     }
  786.                 }
  787.             /* Free up the memory we acquired. */
  788.             for (i = 0; i < numItems; i++)
  789.                 free(data[i]);
  790.             free(data);
  791.             }
  792.         }
  793.     else        /* Keep track of hosts we can't connect to. */
  794.         {
  795.         if (!nogoHead)
  796.             nogoHead = nogoTail = CreateNode(EMPTYSTRING,hostStr,portStr);
  797.         else
  798.             nogoTail = InsertNode(nogoTail,CreateNode(EMPTYSTRING,hostStr,portStr));
  799.         }
  800.  
  801.     if (head != tail)
  802.         tail = RemoveNode(tail);
  803.  
  804. }    /* ProcessMenu */
  805.  
  806. /*****************************************************************************
  807.  * PostTime2Process
  808.  ****************************************************************************/
  809. void PostTime2Process()
  810. {    time_t    theTime,    /* The current time. */
  811.         timeUsed;    /* The time in seconds required for a given run. */
  812.     int    hours,        /* The hours for the process. */
  813.         minutes,    /* The minutes for the process. */
  814.         seconds;    /* The seconds for the process. */
  815.  
  816.     time(&theTime);
  817.     timeUsed = theTime - startTime;
  818.     if (doSearch)
  819.         fprintf(stderr,"The time required to load the index table took ");
  820.     else if (buildIndex)
  821.         fprintf(stderr,"The time required to build the index table took ");
  822.     else
  823.         fprintf(stderr,"The time required to process the menus of %s took ",initialHost);
  824.     hours = (int)(timeUsed / 3600);
  825.     timeUsed -= hours * 3600;
  826.     minutes = (int)(timeUsed / 60);
  827.     timeUsed -= minutes * 60;
  828.     seconds = (int)timeUsed;
  829.     fprintf(stderr,"%d:%d:%d\n",hours,minutes,seconds);
  830.  
  831. }    /* PostTime2Process */
  832.  
  833. /*****************************************************************************
  834.  * InitializeTheWorld initializes the global variables to either 0, NIL, or
  835.  * the respective default value.
  836.  ****************************************************************************/
  837. void InitializeTheWorld()
  838. {
  839.  
  840.     initialHost = selStr = hostStr = portStr =
  841.     fileName = userName = logFile = (char *)NIL;
  842.  
  843.     numSearchHosts = debug = info4dirsOnly = info4allItems = listHosts =
  844.     listHostsNPorts = onlyDoHosts = onlyDoHostsT = buildDataFile = 
  845.     printLineNumbers = printDTree = printDTreeDirs =
  846.     time2process = buildIndex = doSearch = 0;
  847.  
  848.     menuFlag = 1;
  849.  
  850.     searchPort = PORT2USE;
  851.     selStr = EMPTYSTRING;
  852.     portStr = DEFAULTPORT;
  853.  
  854.     head = tail = nogoHead = nogoTail = (List *)NIL;
  855.  
  856. }    /* InitializeTheWorld */
  857.  
  858. /*****************************************************************************
  859.  * main is the heart of this program.
  860.  ****************************************************************************/
  861. int main(argc,argv)
  862.     int    argc;
  863.     char    *argv[];
  864. {
  865.     InitializeTheWorld();
  866.  
  867.     if (GetArguments(argc,argv,&fileName,&logFile))
  868.         if (doSearch)
  869.             DoSearch(fileName,logFile,searchPort);    /* Never returns. */
  870.         else
  871.             {
  872.             if (time2process)
  873.                 time(&startTime);
  874.  
  875.             if (buildIndex)
  876.                 if (CreateWordsTree(fileName))
  877.                     MakeHashTables(fileName,root);
  878.                 else
  879.                     exit(-1);
  880.             else
  881.                 {
  882.                 ProcessMenu(selStr,hostStr,portStr,FIRSTMENU);
  883.                 if (buildDataFile)
  884.                     {
  885.                     fprintf(stderr,"Removing any duplicates from [%s].\n",fileName);
  886.                     DoSystemCall(Mysprint(SORTCOMMAND,fileName,fileName));
  887.                     }
  888.  
  889.                 if (listHosts || listHostsNPorts)
  890.                     PrintTree(root,listHosts + listHostsNPorts);
  891.  
  892.                 if (printDTree)
  893.                     {
  894.                     fprintf(stderr,"********************************************\n");
  895.                     fprintf(stderr,"Now printing the directory tree with the ");
  896.                     if (printDTreeDirs)
  897.                         fprintf(stderr,"directories being served.\n");
  898.                     else
  899.                         fprintf(stderr,"number of directories served.\n");
  900.                     PrintDirTree(dirRoot,PSTR);
  901.                     fprintf(stderr,"********************************************\n");
  902.                     }
  903.  
  904.                 if (nogoHead)
  905.                     {
  906.                     fprintf(stderr,"\nNote: Could not connect to the following host(s):\n");
  907.                     while (nogoHead)
  908.                         {
  909.                         fprintf(stderr,"    %s %s\n",nogoHead->info.hStr,nogoHead->info.pStr);
  910.                         nogoHead = nogoHead->next;
  911.                         }
  912.                     }
  913.  
  914.                 if (buildDataFile)
  915.                     fprintf(stderr,"[%s] now contains the information with duplicates removed\nand points to %ld different gopher menu items\n",fileName,NumberOfLines(fileName));
  916.                                 }
  917.  
  918.             if (time2process)
  919.                 PostTime2Process();
  920.             }
  921.  
  922.     exit(0);
  923.  
  924. }    /* main */
  925.